#include "classes.hpp"
#include <sstream>
#include <typeinfo>
/*

  ---------------------- HUMAIN ----------------------

*/


/*   --- Constructeur ---    */
humain::humain(): boisson(""), argent(0){
  nom=new char[1];
  strcpy(nom, "");
}
humain::humain(const char* n, string b): boisson (b), argent (0){
  nom = new char[strlen(n)+1];
  strcpy(nom, n);
}
humain::humain(const char* n, int a): argent(a){
  nom = new char[strlen(n)+1];
  strcpy(nom, n);
}
humain::humain(const char* n, int a, string b): argent(a), boisson(b){
  nom = new char[strlen(n)+1];
  strcpy(nom, n);
}

humain & humain::operator =(const humain &h){
  if( this!= &h){
    if (nom) delete [] nom;
    nom = new char[strlen(h.nom)+1];
    strcpy(nom, h.nom);
    boisson=h.boisson;
    argent=h.argent;
  }
  return *this;
}

humain::humain(const humain &h){
  nom=new char[strlen(h.nom)+1];
  strcpy (nom,h.nom);
  boisson=h.boisson;
  argent=h.argent;
}
/*   --- Fin constructeur --- */
char* humain:: get_nom() const {return nom;}
string humain::get_boisson() const {return boisson;}
int humain::get_argent() const {return argent;}
void humain::set_nom(char * n){nom=n;}
void humain::set_boisson(string b){boisson=b;}
void humain::set_argent(int a){argent=a;}
void humain::affiche(ostream &s) const {
  s<<"Nom : "<<nom<<"\nBoisson : "<<boisson<<"\nArgent : "<<argent<<endl;
}

humain::~humain(){
  delete [] nom;
}

void humain::parler(string discours)const {
  cout<<nom<<" : "<<discours<<endl;
}

void humain::dire_bonjour() const {
  ostringstream oss;
  oss<<"Bonjour, je suis " << nom <<" ,j'aime boire du "<<boisson<<" et j'ai "<<argent<<" écus.";
  parler(oss.str());
}

void humain::boire() const{
  ostringstream oss;
  oss<<"Mmm, un bon verre de "<< boisson<< "! Gloups!";
  parler(oss.str());
}
 
ostream & operator <<(ostream &s,const humain &h ){
  h.affiche(s);
  return s;
}

void humain::perdre_argent(int x){
  if (x>argent) x=argent;
  argent-=x;
}

void humain::gagner_argent(int x){
  argent+=x;
}



/*

  ------------------------  COMMERCANT  ------------------------------

*/

commercant::commercant(const char* n, int a): humain(n, a,"Thé")
{}
commercant::commercant(const commercant &c){*this=c;}
void commercant::se_faire_extorquer(){
  set_argent(0);
  parler("J'ai tout perdu, le monde est vraiment injuste !");
}
void commercant::recevoir_argent(int a){
  gagner_argent(a);
  parler("Merci beaucoup Mr Ronin !");
}

commercant & commercant::operator =( const commercant &c){
  if( this != &c){
    humain *h = this;
    *h=c;
  }
  return *this;
}

void commercant::donner( int a, humain *h ){}
void commercant::action( humain *h ){}

void commercant::dire_bonjour() const {
  humain::dire_bonjour();
}
/*

  ------------------------  YAKUZA  ------------------------------

*/

yakuza::yakuza(const char* n, int a, string b, int rep, string c): humain(n,a,b), reputation(rep), clan(c)
{}
yakuza::yakuza(const char* n, int a, string b, string c): humain(n,a,b), reputation(0), clan(c)
{}
void yakuza::extorquer( commercant &c){
  set_argent(get_argent()+c.get_argent());
  c.se_faire_extorquer();
  reputation++;
  parler("Je viens de prendre tout l'argent d'un commercant ! :)");
}
yakuza::~yakuza(){}

string yakuza::get_clan()const{ return clan;}
int yakuza::get_reputation()const{ return reputation;}
void yakuza::set_clan( string nouveau_clan){clan=nouveau_clan;}
void yakuza::set_reputation(int nouvelle_reput){ reputation=nouvelle_reput;}
void yakuza::affiche(ostream &s) const{
  humain::affiche(s);
  cout<<"Clan : "<<clan<<endl;
  cout<<"Reputation : "<<reputation<<endl;
}
void yakuza::gagner(){
  parler("J'ai gagné !");
  set_reputation(get_reputation()+1);
}
void yakuza::perdre(){
  parler("J'ai perdu !");
  set_argent(0);
  set_reputation(get_reputation()-1);
}

yakuza & yakuza::operator =( const yakuza &y){
  if( this != &y){
    this-> ~yakuza();
    humain *h = this;
    *h=y;
    clan=y.clan;
    reputation=y.reputation;
  }
  return *this;
}
void yakuza::dire_bonjour()const{
  humain::dire_bonjour();
  ostringstream oss;
  if (clan!="")
    oss<<"J'appartiens au clan " <<clan<<". ";
  
  oss<<"J'ai une réputation de "<< reputation;
  parler(oss.str());
}


void yakuza::donner( int a, humain *h ){}
void yakuza::action( humain *h ){
  extorquer(*((commercant *)h));
}

/*

  ------------------------  RONIN  ------------------------------

*/

ronin::ronin(const char *n, int a, string b, int h): humain(n,a,b), honneur(h){}
ronin::ronin(const char *n, int a, string b): humain(n,a,b), honneur(1){};

int ronin::get_honneur()const{ return honneur;}
void ronin::set_honneur(int h){ honneur=h;}
void ronin::provoquer(yakuza &y){
  if(2*honneur > y.get_reputation()){
    set_argent(get_argent()+y.get_argent());
    honneur++;
    parler("J'ai gagné contre un yakuza ! :-)");
    y.perdre();
  }
  else {
    honneur--;
    parler("J'ai perdu contre un yakuza ! :-(");
    y.gagner();
  }
  
}
void ronin::affiche(ostream &s) const{
  humain::affiche(s);
  cout<<"Honneur : "<<honneur<<endl;  
}
ronin & ronin::operator =( const ronin &r){
  if( this != &r){
    this->~ronin();
    humain *h = this;
    *h=r;
    honneur=r.honneur;
  }
  return *this;
}
ronin::~ronin(){}

void ronin::dire_bonjour() const{
  ostringstream oss;
  humain::dire_bonjour();

  oss<<"J'ai une honneur de "<<honneur<<".";
  parler(oss.str());
}

void ronin::donner( int a, humain *h ){
  commercant *c=(commercant*)h;
  c->recevoir_argent(a);
  perdre_argent(a);
}
void ronin::action( humain *h ){
  provoquer(*((yakuza*)h));
}

/*

  ------------------------  SAMURAI  ------------------------------

*/

samurai::samurai(const char* n,  int a, string b, int h, string s): ronin(n,a,b,h), seigneur(s){}
samurai::samurai(const char* n,  int a, string b, string s): ronin(n,a,b), seigneur(s){}

void samurai::affiche(ostream &s)const{
  ronin::affiche(s);
  cout<<"Seigneur : "<<seigneur<<endl;
}
void samurai::boire(string b) const{
  ostringstream oss; 
  oss<<"Mmm, un bon verre de "<< b << "! Gloups !";
  parler(oss.str());
}

string samurai::get_seigneur()const {return seigneur;};
void samurai::set_seigneur(string s){ seigneur=s;};
samurai::~samurai(){}
samurai & samurai::operator =( const samurai &s){
  if( this != &s){
    this->~samurai();
    ronin *h = this;
    *h=s;
    seigneur=s.seigneur;
  }
  return *this;
}

void samurai::dire_bonjour() const {
  ronin::dire_bonjour();
  ostringstream oss;
  oss<<"Mon seigneur est " << seigneur;
  parler(oss.str());
}

void samurai::donner( int a, humain *h ){
  commercant *c=(commercant*)h;
  c->recevoir_argent(a);
  perdre_argent(a);
}
void samurai::action( humain *h ){
  provoquer(*((yakuza*)h));
}

/*

  ------------------------  GRILLE   ------------------------------

*/

void grille::say_hello() const{
  for (int i=0; i<taille; i++){
    for (int j=0; j<taille;j++){
      if(planet[i][j]!=0){
	planet[i][j]->dire_bonjour();
	cout<<'['<<i<<"] ["<<j<<']'<<endl; // endroit ou il se trouve !
      }
    }
  }
}

void grille::placer(int k ){
  humain *h;
  switch (k){
  case 0: h= new commercant("Commercant",0);break;
  case 1: h= new ronin("Ronin", 0, "Eau");break;
  case 2: h= new yakuza("Yakuza", 0, "Eau", 0, "Pas de clan");break;
  case 3: h= new samurai("Samurai", 0, "Eau", "Pas de seigneur");break;
  }
  int i=0, j=0;
  do{
    i =  rand() %taille;
    j =  rand() %taille;
  }
  while (planet[i][j]!=0);
  planet[i][j]=h;
  // Probleme avec le humain *h ?
}
grille::~grille(){
  for (int i=0; i<taille; i++){
    for (int j=0; j<taille;j++){
      delete planet[i][j];
    }
  }
}

void grille::affiche_grille(){
  
  for (int i=0; i<taille; i++){
    for (int j=0; j<taille;j++){
      if(planet[i][j]!=0){
	cout<<planet[i][j]->get_nom()<<'['<<i<<"] ["<<j<<']'<<endl;
      }
    }
  }
}
// --------- move left --------------
void grille::move_left(int i, int j){
  cout<<"move_left()"<<endl;
  humain *aux[taille][taille];
  int x=i,y=j;
  for ( x=0; x<taille; x++)
    for ( y=0; y<taille;y++)
      aux[x][y]=planet[x][y];
  x=i;
  y=j;
  if(planet[x][y-1]!=0){
    planet[x][y]->action(planet[x][y-1]);
    aux[x][y]=aux[x][y-1];
    planet[x][y-1]=planet[x][y];
    planet[x][y]=aux[x][y];
  }
  else
    planet[x][y-1]=planet[x][y];
  
  for (int i=0; i<taille; i++)
    for (int j=0; j<taille;j++)
      delete aux[i][j];
}


// --------- move right --------------
void grille::move_right(int i, int j){
  cout<<"move_right()"<<endl;
  humain *aux[taille][taille];
  int x=i,y=j;
  for ( x=0; x<taille; x++)
    for ( y=0; y<taille;y++)
      aux[x][y]=planet[x][y];
  x=i;
  y=j;
  if(planet[x][y+1]!=0){
    planet[x][y]->action(planet[x][y+1]);
    aux[x][y]=aux[x][y+1];
    planet[x][y+1]=planet[x][y];
    planet[x][y]=aux[x][y];
  }
  else
    planet[x][y+1]=planet[x][y];
  
  for (int i=0; i<taille; i++)
    for (int j=0; j<taille;j++)
      delete aux[i][j];
}


// --------- move up --------------
void grille::move_up(int i, int j){  
  cout<<"move_up()"<<endl;
  humain *aux[taille][taille];
  int x,y;
  for ( x=0; x<taille; x++)
    for ( y=0; y<taille;y++)
      aux[x][y]=planet[x][y];
  x=i;
  y=j;
  if(planet[x-1][y]!=0){
    planet[x][y]->action(planet[x-1][y]);
    aux[x][y]=aux[x-1][y];
    planet[x-1][y]=planet[x][y];
    planet[x][y]=aux[x][y];
  }
  else
    planet[x-1][y]=planet[x][y];
  
  for (int i=0; i<taille; i++)
    for (int j=0; j<taille;j++)
      delete aux[i][j];
}


// --------- move down --------------
void grille::move_down(int i, int j){
  cout<<"move_down()"<<endl;
  humain *aux[taille][taille];
  int x=i,y=j;
  for ( x=0; x<taille; x++)
    for ( y=0; y<taille;y++)
      aux[x][y]=planet[x][y];
  x=i;
  y=j;
  if(planet[x+1][y]!=0){
    planet[x][y]->action(planet[x+1][y]);
    aux[x][y]=aux[x+1][y];
    planet[x+1][y]=planet[x][y];
    planet[x][y]=aux[x][y];
  }
  else
    planet[x+1][y]=planet[x][y];
  
  for (int i=0; i<taille; i++)
    for (int j=0; j<taille;j++)
      delete aux[i][j];
}

void grille::rd_move(int i, int j){
  cout<<"rd_move() !"<<endl;
  srand(time(NULL)); 
  int rd=0;
  rd= rand()%4;
  switch(rd){
  case 0: if (i==0) rd_move(i,j);
    else {
      cout<<"call->move_left!!!"<<endl;
      move_left(i,j); }break;
  case 1: if (i==4) rd_move(i,j);
    else {
      cout<<"call->move_right!!!"<<endl;
      move_right(i,j);}break;
  case 2: if (j==0) rd_move(i,j);
    else{
      cout<<"call->move_up!!!"<<endl;
      move_up(i,j);}break;
  case 3: if (j==4) rd_move(i,j);
    else{
      cout<<"call->move_down!!!"<<endl;
      move_down(i,j);}break;
  }
}

void grille::modif_grille(){
  cout<<"modif_grille()"<<endl;
  srand(time(NULL));
  int i,j;
  int nb_mouvement=1;
  // nb_mouvement=rand () %5;
  for(int k=0; k<nb_mouvement;k++){
    for ( i=0; i<taille; i++)
      for ( j=0; j<taille;j++)
	if(planet[i][j]!=0)
	  rd_move(i,j);
  }
}
  
